/* 
 * File:   ThreadRldEvent.cpp
 * Author: batista
 * 
 * Created on 7 de Março de 2013, 11:56
 */

#include "ThreadRldEvent.h"

/**
 * Metodo construtor..
 * Onde é chamado todo o processo em sua 
 * inicialização.
 */
ThreadRldEvent::ThreadRldEvent() : JoinableThread() {
    //    
    timet = new TimeUtil();

    ShowMessage("Construtor(): Abrindo Porta Serial()!!", COLOR_BLUE, COLOR_PINK);
    //
    startPort();
    //    
}

/**
 * Metodo destrutor..
 * Onde pode ser finalizado processos.
 */
ThreadRldEvent::~ThreadRldEvent() {
}

void ThreadRldEvent::startPort() {
    //
    m_port = new SerialPorts();

    //Seta a porta a ser aberta
    if (m_port->getSerial_port().empty())
        m_port->setSerial_port("/dev/ttyS0");

    //seta o baudrate
    if (m_port->getBaud_rate().empty())
        m_port->setBaud_rate("9600");
    //
    //Abre a porta
    m_port->OpenPort();
    //
}

void ThreadRldEvent::run() {
    std::string msg;
    //
    ShowMessage("INICIANDO (ThreadRldEvent)....!!!", COLOR_BLUE, COLOR_PINK);
    ::sleep(2);

    while (1) {
        ShowMessage("INICIANDO O PROCESSO DE CAPTURA....!!!", COLOR_BLUE, COLOR_PINK);

        /**
         * Inicia o processo de captura.
         * Se passa pela primeira parte, 
         * vai para segunda, onde pega 
         * o evento.
         */
        if (PrepareRldEvent()) {

        }

        /**
         * Se acontecer algo com a porta.
         * Fechar ela e abre novamente..
         */
        if (!m_port->IsOpen()) {
            //
            msg = "Manutencao na Porta(): Abrindo Porta Serial()!!";
            //
            ShowMessage(msg, COLOR_BLUE, COLOR_RED);
            //
            dirfl->CreateLogFile("SERIAL-LOG-CAP-ERRO", msg);
            //Fecha a porta
            startPort();
        }

    }
}

/**
 * Metodo responsavel por fazer a leitura dos eventos da Rauland
 * e armazenar em uma tabela temporaria na memoria
 * para ser gerenciado por uma thread gerenciadora.
 */

bool ThreadRldEvent::RunRldEventCap() {
    DirFile dirfl;
    char c;

    //Seta pasta de gravação de logs
    dirfl.setFolder_write("/Logs/Rld/");
    //
    bool LF1 = false, LF2 = false, LF3 = false, LF4 = false;
    //
    bool v1B_Pg1 = false, vLF_Pg1 = false;

    int count = 1;
    //
    // QChar c;
    char start_pg[] = "\r\r"; //<LF><CR><CR>
    char start_pg1[] = "ID=";
    char start_pg2[] = "\x0d\x0d\x06\x0d"; //<CR><MSG><CR><ACK><CR>
    char start_pg3[] = "\x1b\x5b\x70\x0d"; //<ESC><[><p><CR>

    //dirfl.CreateLogCap('?', 'w', 's');
    //
    //m_port->WriteBuffer(start_pg);

    while (m_port->IsOpen()) {

        //Faz a leitura da porta
        c = m_port->ReadChar();

        //
        if (c == 'B' || c == 'Y' || c == 'E') {
            while (1) {
                //
                c = m_port->ReadChar();
                //
                if (c == 0x0a && LF1 == false) {
                    LF1 = true;
                    c = '\0';
                }
                //
                if (c == 0x0a && LF2 == false) {
                    LF2 = true;
                    c = '\0';
                }
                //
                if (c == 0x0a && LF3 == false) {
                    LF3 = true;
                    c = '\0';
                }
                //
                if (c == 0x0a && LF4 == false) {
                    LF4 = true;
                    c = '\0';
                }

                if (LF1 == true && LF2 == true && LF3 == true && LF4 == true) {
                    ShowMessage("Encontrou BYE<LF><EOT><LF><LF><LF>", COLOR_BLUE, COLOR_GREEN);
                    count = 1;
                    break;
                }

                /**
                 * Se nao coneguiu pegar 
                 * <LF><EOT><LF><LF><LF> nos
                 * ultimos 24 bytes..
                 * Sai loop.
                 * @return 
                 */
                if (count == 24) {
                    count = 1;
                    break;
                }
                //
                count++;
            }
        }


        if (LF1 == true && LF2 == true && LF3 == true && LF4 == true) {
            //
            ShowMessage("Encontrou <LF>, Enviado ID=", COLOR_BLUE, COLOR_GREEN);
            //cout << "Encontrou <LF>, Enviado ID=" << endl;
            //
            m_port->WriteBuffer(start_pg1); //aqui passo o char para variavel
            // 
            while (1) {
                //
                ShowMessage("StartReadPager(): Aguardando <PG1>!!", COLOR_BLUE, COLOR_PINK);
                //
                c = m_port->ReadChar();
                //
                if (c == 0x1b) {
                    v1B_Pg1 = true;
                }
                //
                if (c == 0x0a) {
                    vLF_Pg1 = true;
                }
                //
                if (v1B_Pg1 == true && vLF_Pg1 == true) {
                    //
                    ShowMessage("Encontrou <PG1>", COLOR_BLUE, COLOR_GREEN);
                    //cout << "Encontrou <PG1>" << endl;
                    ShowMessage("Agradeco Gravando: <CR><CR><ACK><CR>", COLOR_BLUE, COLOR_GREEN);
                    //cout << "Agradeco Gravando: <CR><CR><ACK><CR>" << endl;
                    m_port->WriteBuffer(start_pg2); //<cr><cr><ack><cr>
                    //
                    ShowMessage("Digo para Enviar a Mensagem Gravando <ESC>[p<CR>", COLOR_BLUE, COLOR_GREEN);
                    // cout << "Digo para Enviar a Mensagem Gravando <ESC>[p<CR>" << endl;
                    m_port->WriteBuffer(start_pg3); //<esc><[p<cr>
                    //                   
                    return true;
                }

                /**
                 * Se recebeu 5 bytes e nao encontrou
                 * <ESC>PG1<CR>, grava novamente ID=
                 * @return 
                 */
                if (count == 6) {
                    //
                    ShowMessage("Atingido 6 BYTES Sem <ESC>PG1<CR>, Gravando <ID=> ", COLOR_BLUE, COLOR_RED);
                    //
                    m_port->WriteBuffer(start_pg1); //aqui passo o char para variavel
                }

                //Grava o processo inicial novamente, quando atingir 8 segundos
                if (count == 12) {
                    //
                    ShowMessage("Atingido 12 BYTES Sem <ESC>PG1<CR>, Gravando <ID=> ", COLOR_BLUE, COLOR_RED);
                    //
                    m_port->WriteBuffer(start_pg1); //aqui passo o char para variavel
                }

                /**
                 * Se tudo correr bem, vai receber 5 bytes 
                 * referente a  <ESC>PG1<CR> e sair.
                 * Se nao conseguir receber os 5 bytes
                 * nos ultimos 15 bites lidos... Retorna 
                 * ao inicio da aplicacao...Isso sera feito 
                 * para nao correr o risco de ficar preso
                 * aguardando para sempre. 
                 * @return 
                 */
                if (count == 18) {
                    //
                    ShowMessage("Atingido limite 18 BYTES Sem <ESC>PG1<CR>, Descartando Espera!!", COLOR_BLUE, COLOR_RED);
                    //
                    return false;
                }

                //Incrementa o contador de bytes
                count++;
            }
        }
        //
        ShowMessage("AGUARDANDO <CR> OU <LF>!!", COLOR_BLUE, COLOR_PINK);
        //
    }//Fim while Inicio

    return true;
}

/**
 * Metodo responsavel por pegar os dados para 
 * montar o evento da Rauland.
 * @return 
 */
bool ThreadRldEvent::PrepareRldEvent() {
    //
    event = new Event();
    std::string pager_code, ward_short_name, room_name, event_msg = "";
    std::string data_captured, data_cap_erro;
    char c;
    int count_hex = 0;
    //
    //
    while (1) {
        //
        //
        while (1) {
            //
            ShowMessage("Em (EndReadPager), Aguardando <STX> !", COLOR_BLUE, COLOR_GREEN);
            //
            c = m_port->ReadChar();
            //
            /**
             * Aqui ele entra e finaliza a segunda parte
             * quando encontrou um <STX>
             */
            if (c == 0x02) {//<STX> = HEX(02)
                ShowMessage("Encontrou <STX>, Segunda Parte OK!", COLOR_BLUE, COLOR_GREEN);
                //cout << "Encontrou <STX>, Segunda Parte OK!" << endl;
                break;
            }

            /**
             * Caso o PIP Rauland finalize o 
             * processo de envio emquanto 
             * tive aguardando mensagens
             * Volta para o inicio em RunRldEventCap().
             * @return 
             */
            if (c == 'B') {
                RunRldEventCap();
            }
        }


        ShowMessage("Pegando codigo do Pager!", COLOR_BLUE, COLOR_PINK);

        /**
         * Encontrou um <STX> = HEX(02)
         * Entao comeca a pegar o numero do pager
         * até encontrar um <LF>, que
         * deveria ser um <CR>
         */
        while (m_port->IsOpen()) {//<STX>123<CR>ABC<CR><ETX>17;<CR>

            c = m_port->ReadChar();

            count_hex++;
            //
            cout << FG_GREEN << hex << (int) c << END << endl;
            //
            if (c == 0x0d || c == 0x0a) {//<LF>=10=<0X0a> <CR>=13=<0x0d>
                //
                ShowMessage("Page_code...: " + pager_code, COLOR_BLUE, COLOR_PINK);
                //
                count_hex = 0;
                break;
            }

            /**
             * Se chegar a 6 chars e nao pegou o codigo do pager... 
             * Termina com erro
             * @return 
             */
            if (count_hex == 6) {
                dirfl->CreateLogFile("SERIAL-LOG-CAP-ERRO", pager_code);
                c = '\0';
                count_hex = 0;
                break;
            }

            //
            pager_code += c;
            //
        }

        /**
         * Aqui pega o numero da Ala,
         * que deve ser de ate tres caracteres
         * apos encontrar um <LF>
         */
        if (c == 0x0d || c == 0x0a) {//<LF>=10=<0X0a> <CR>=13=<0x0d>
            //
            ShowMessage("Pegando codigo da Ala!", COLOR_BLUE, COLOR_PINK);
            //
            while (m_port->IsOpen()) {
                //
                c = m_port->ReadChar();
                //
                count_hex++;

                ward_short_name += c;
                //
                cout << FG_GREEN << hex << (int) c << END << endl;
                //            
                //
                if (ward_short_name.size() == 2) {//Tres caracteres para ala      
                    //
                    ShowMessage(ward_short_name, COLOR_BLUE, COLOR_PINK);
                    count_hex = 0;
                    //
                    break;
                }
                /**
                 * Se chegar a 6 chars e nao pegou o codigo da ala... 
                 * Termina com erro
                 * @return 
                 */
                if (count_hex == 6) {
                    dirfl->CreateLogFile("SERIAL-LOG-CAP-ERRO", ward_short_name);
                    c = '\0';
                    count_hex = 0;
                    break;
                }
                // 
            }
        }//Fim da Ala

        /**
         * Aqui pega o numero do quarto
         * ate encontrar <ESP>
         */
        ShowMessage("Pegando codigo do quarto!", COLOR_BLUE, COLOR_PINK);

        if (ward_short_name.size() == 2) {
            //
            while (m_port->IsOpen()) {
                //
                c = m_port->ReadChar();

                count_hex++;
                //
                cout << FG_GREEN << hex << (int) c << END << endl;
                //            
                //
                if (c == 0x20) {//<ESP> = HEX(20)
                    ShowMessage(room_name, COLOR_BLUE, COLOR_PINK);
                    count_hex = 0;
                    //
                    break;
                }
                
                /**
                 * Se chegar a 10 chars e nao pegou o codigo do quarto... 
                 * Termina com erro
                 * @return 
                 */
                if (count_hex == 10) {
                    dirfl->CreateLogFile("SERIAL-LOG-CAP-ERRO", room_name);
                    c = '\0';
                    count_hex = 0;
                    break;
                }
                //
                room_name += c;
            }
        }


        /**
         * Aqui pega a mensagem
         * ate encontrar um <LF>
         * que deveria ser <CR>
         */
        if (c == 0x20) {//<ESP> = HEX(20)
            ShowMessage("Pegando mensagem de evento!", COLOR_BLUE, COLOR_PINK);

            while (m_port->IsOpen()) {//<STX>123<CR>ABC<CR><ETX>17;<CR>
                //
                c = m_port->ReadChar();

                count_hex++;
                //
                cout << FG_GREEN << hex << (int) c << END << endl;
                //
                //
                if (c == 0x0a || c == 0x0d) {//<cr>
                    //
                    count_hex = 0;
                    ShowMessage(event_msg, COLOR_BLUE, COLOR_PINK);
                    break;
                }

                /**
                 * Se chegar a 30 chars e nao pegou o codigo do pager... 
                 * Termina com erro
                 * @return 
                 */
                if (count_hex == 30) {
                    dirfl->CreateLogFile("SERIAL-LOG-CAP-ERRO", event_msg);
                    c = '\0';
                    count_hex = 0;
                    break;
                }
                // 
                event_msg += c;
            }
        }

        /**
         * Se o ultimo byte lido foi um <ETX>
         * Hex(0x03), Significa que finaliza a 
         * leitura dos dados para o pager com
         * sucesso. Entra no if, retorna os 
         * dados e status de true.
         * @return 
         */
        if ((c == 0x0a || c == 0x0d) ||
                (pager_code.size() == 2 &&
                ward_short_name.size() == 2 &&
                !room_name.empty()
                && !event_msg.empty())) {


            /**
             * Caso seja evento de cancelamento, seta 
             * ele como evento de cancelamento.
             * @return 
             */
            if (event_msg == "Cancel") {
                ShowMessage("[      EVENTO DE CANCELAMENTO       ]", COLOR_BLUE, COLOR_RED);
                event->SetEventCancel(true);
            } else {
                //
                event->SetEventCancel(false);
            }

            //Seta da e hora atual
            event->SetDate_Time_Called(timet->getTime());

            //Seta o codigo do Pager
            event->SetPagerCode(pager_code);

            //Seta o codigo da ala
            event->SetWardSigla(ward_short_name);

            //Seta o nome do quarto
            event->SetRoomName(room_name);

            //Seta o código do leito
            event->SetRoomBedCode("1");

            //Seta a mensagem de evento
            event->SetEventMessage(event_msg);

            data_captured = "Evento Capturado: "
                    "\nPager..: " + event->GetPagerCode() +
                    "\nData...: " + event->GetDate_Time_Called() +
                    "\nAla....: " + event->GetWardSigla() +
                    "\nQuarto.: " + event->GetRoomName() +
                    "\nEvento.: " + event->GetEventMessage() + "\n\n";
            
            /**
             * Finaliza o processo de captura
             * mandando comando de que recebeu tudo
             * okay, se nao o PIP manda novamente
             * a mensagem.
             * @return 
             */
            if (EndReadPager()) {
                
                /**
                 * So sera adicionado o evento se ele nao for
                 * repetido para mesma Ala, Quarto e Evento.
                 * Se nao, sera descartado e gravado na pasta
                 * de logs Rm.
                 * @return 
                 */
                if (!dbcon->validEventCapRldInSqLite(event)) {


                    //Seta pasta de gravação de logs
                    dirfl->setFolder_write("/Logs/Rld/");
                    dirfl->CreateLogFile("SERIAL-LOG-CAPRLD-OK", data_captured);
                    //
                    cout << '\n' << FG_GREEN
                            << "\nPager..: " << pager_code
                            << "\nAla....: " << ward_short_name
                            << "\nQuarto.: " << room_name
                            << "\nEvento.: " << event_msg << END;
                    /**
                     * Atualiza o evento para Ala atual.
                     * Da proxima vez ele vai estar la e
                     * nao pode ser adicionado
                     * @return 
                     */
                    dbcon->runUpdateEventValidInSqLite(event);

                    //
                    ShowMessage("Adicionando Evento para Tabela Temporaria (event_rauland)!!", COLOR_BLUE, COLOR_PINK);
                    //
                    dbcon->runAddEventInSqLite(event);
                    //

                    ShowMessage("[             FIM DO PROCESSO DE CAPTURA COM SUCESSO!!!            ]", COLOR_BLUE, COLOR_PINK);

                    //
                } else {
                    //
                    data_captured = "Evento Capturado: "
                            "\nPager..: " + pager_code +
                            "\nData...: " + timet->getTime() +
                            "\nAla....: " + ward_short_name +
                            "\nQuarto.: " + room_name +
                            "\nEvento.: " + event_msg + "\n\n";
                    //
                    //Seta pasta de gravação de logs
                    dirfl->setFolder_write("/Logs/Rld/Rm/");
                    dirfl->CreateLogFile("SERIAL-LOG-CAPRLRM-OK", data_captured);
                    //               
                }
            } else {
                ShowMessage("[             NAO FOI POSSIVEL FINALIZAR NORMAL!!!                 ]", COLOR_BLUE, COLOR_PINK);
            }
            //
        } else {
            //
            data_cap_erro = "Evento Capturado: "
                    "\nPager..: " + event->GetPagerCode() +
                    "\nData...: " + event->GetDate_Time_Called() +
                    "\nAla....: " + event->GetWardSigla() +
                    "\nQuarto.: " + event->GetRoomName() +
                    "\nEvento.: " + event->GetEventMessage() + "\n\n";

            //
            dirfl->CreateLogFile("SERIAL-LOG-CAP-ERRO", data_cap_erro);
            //
            ShowMessage("[                FIM, NAO FOI POSSIVEL PEGAR OS DADOS!!!                 ]", COLOR_BLUE, COLOR_PINK);
        }

        //Limpa tudo
        pager_code.clear();
        ward_short_name.clear();
        room_name.clear();
        event_msg.clear();
        data_captured.clear();
        data_cap_erro.clear();
        count_hex = 0;
    }
    //
    return true;
}

/**
 * Metodo responsavel por fazer a segunda parte
 * da comunicação do protocolo tap.
 * Finaliza o processo de comunicação com o Pager.
 * @return true or false
 */
bool ThreadRldEvent::EndReadPager() {
    //
    int count_hex = 0;
    //
    char c;
    char start_pg4[] = "\x0d\x06\x0d"; // <CR><ACK><CR>finaliza o dialogo
    // char end_pg5[] = "\x0d\x1b\x04\x0d"; //<CR><ESC><EOT><CR>

    /**
     * Se a porta ainda estiver
     * accessivel, entra para finalizar
     * os processos.
     * @return 
     */
    if (m_port->IsOpen()) {

        ShowMessage("Finalizando o Processo Apos a Captura dos Dados!!!", COLOR_BLUE, COLOR_PINK);

        /**
         * Apos ter encontrado um <ETX>, percorre
         * o restante do buffer ate encontrar um <CR>
         * ou <LF>, que significa que recebeu todos os 
         * dados do pager.
         * Aguarda receber um <CR> ou <LF>, ai
         * envia uma resposta dizendo que foi aceito
         * com: (211 Page accepted) <CR><ACK><CR>
         */
        //Fica no while ate finaliza o buffer da porta serial
        while (m_port->IsOpen()) {//<STX>123<CR>ABC<CR><ETX>17;<CR>
            //
            c = m_port->ReadChar();

            count_hex++;
            //
            cout << FG_GREEN << hex << (int) c << END << endl;
            //
            //
            if (c == 0x0d || c == 0x0a) {//<ETX>
                //
                ShowMessage("Gravando --> <CR><ACK><CR>", COLOR_BLUE, COLOR_GREEN);
                m_port->WriteBuffer(start_pg4); //<CR><ACK><CR>
                //
                count_hex = 0;
                ShowMessage("FINALIZADO O BUFFER DE LEITURA OKAY!!", COLOR_BLUE, COLOR_PINK);
                return true;
            }

            /**
             * Se chegar a 6 chars e nao pegou o codigo do pager... 
             * Termina com erro
             * @return 
             */
            if (count_hex == 6) {
                dirfl->CreateLogFile("SERIAL-LOG-CAP-ERRO", "Nao conseguio finalizar normal!!");
                c = '\0';
                count_hex = 0;
                //
                return false;
            }
            // 
        }
    }

    return false;
}


/*******************************************************************************
 *                                                                             *
 *          Remote Entry Device      |      Paging Terminal                    *
 *                                                                             *
 * 1) Dials paging terminal                Modem Answers                       *
 * 2) Modem Connects                                                           *
 * 3) <CR>                                                                     *
 * 4)                                      ID=                                 *
 * 5a) <ESC>PG1<CR>                                                            *
 * 6)                                    <CR>Thank you for calling the PCIA<CR>* 
 *                                       <ACK><CR>                             *
 *                                                                             *
 * 7)                                    <ESC>[p<CR>                           *
 *                                                                             *
 * 8) <STX>123<CR>ABC<CR><ETX>17;<CR>                                          *
 *                                       211 Page accepted <CR>                *
 *                                       <ACK><CR>                             *
 *                                                                             *
 * 9) <EOT><CR>                                                                *
 * 10a)                                  115 Thank you for calling <CR>        *
 * 10b)                                  <ESC><EOT><CR>                        * 
 *                                                                             *
 *                                                                             *
 * 11)                                   Drops Carrier                         *
 * Drops Carrier                                                               *
 *                                                                             *
 ******************************************************************************/